<?php

namespace App\Task;

use App\Cache\RedisKey;
use App\Helpers\ConfigUtil;
use App\Helpers\EventUtil;
use App\Helpers\RedisUtil;
use App\Model\CallBase;
use App\Model\Message;
use App\Model\Service\ConsumeService;
use App\Model\UserCoin;
use App\Model\UserFreeCall;
use App\Model\VideoCall;
use App\Model\VoiceCall;


class CheckTaskBase
{
    /**
     * 处理单条记录
     */
    protected function runCheck($callingLog)
    {
        $callCls = $callingLog['call_type'] == VoiceCall::CALL_TYPE ? VoiceCall::class : VideoCall::class;
        //拨打用户费用检测
        $userCoin = UserCoin::getUserInfo($callingLog['user_id']);
        if (!$userCoin) {
            log_info(__CLASS__ . "==noCoinLog==UserId:" . $callingLog['user_id'] . "=={$callCls}==LogId:" . $callingLog['id']);
            return false;
        }

        //该次通话的单价
        $coinSetting = $callingLog['coin_setting'];
        if ($coinSetting == 0) {
            //挂断电话
            Message::sendSlient($callingLog['user_id'], 'HANGUP_CALL');
            //系统消息
            Message::pushOfficialMsg($callingLog['user_id'], "该次通话单价设置异常，通话已挂断");
            log_info(__METHOD__ . "==coinSettingError==coin_setting:{$coinSetting}=={$callCls}==LogId:{$callingLog['id']}");
        }

        //当前累计消费
        $totalCost = CallBase::calTotalCost($callingLog, $coinSetting);

        //支付完后剩余金币
        $remainCoin = $userCoin['real_total_coin'] - $totalCost;

        //冻结金币
        UserCoin::freezeCoin($callingLog['user_id'], $totalCost);

        //当前通话时间（秒）
        $callSeconds = time() - $callingLog['answer_time'];
        //当前计费分钟数（分）
        $costMinutes = CallBase::calTotalMinutes($callingLog);
        //离计费分钟数相差的秒数
        $remainSeconds = $costMinutes * 60 - $callSeconds;

        //提示金额
        $tipCoin = $coinSetting * ConfigUtil::getTipRemainMinuts();
        //余额不足1分钟，且剩余时间不足10秒
        if (
            $remainCoin < 0 ||
            ($remainCoin < $coinSetting && $remainSeconds <= 10)
        ) {
            //结算通话
            $this->endCall($callingLog, $callCls);
            //金币不够
            Message::sendSlient($callingLog['user_id'], 'NO_COIN');
            //系统消息
            // Message::pushSystem($callingLog['user_id'], "金币余额不足，通话已结束~");
            log_info(__METHOD__ . "==overtime==Coin:{$userCoin['total_coin']}==TotalCost:{$totalCost}==CallSeconds:{$callSeconds}==CostMinutes:{$costMinutes}=={$callCls}==LogId:{$callingLog['id']}");
        }
        //时间不够3分钟
        elseif ($remainCoin < $tipCoin) {
            //透传通知余额不够-主叫方
            Message::sendSlient($callingLog['user_id'], 'LACK_COIN');
            //系统消息
            // Message::pushSystem($callingLog['user_id'], "金币余额不足，请您及时充值哦~");
            log_info(__METHOD__ . "==lacktime==Coin:{$userCoin['total_coin']}==TotalCost:{$totalCost}=={$callCls}==LogId:{$callingLog['id']}");
        }
        //时间足够
        else {
            //金币足够
            Message::sendSlient($callingLog['user_id'], 'ENOUGH_COIN');
            log_info(__METHOD__ . "==passcheck==Coin:{$userCoin['total_coin']}==TotalCost:{$totalCost}=={$callCls}==LogId:{$callingLog['id']}");
        }

        return true;
    }

    /**
     * 关闭无效话单
     */
    protected function runClose($callType = VoiceCall::CALL_TYPE)
    {
        $callCls = $callType == VoiceCall::CALL_TYPE ? VoiceCall::class : VideoCall::class;
        //无效记录状态（60秒内没有接通）- 排除各种匹配入口的：随心聊，免费福利等
        $where = [
            ['status', CallBase::STATUS_NO_PICK],
            // ['from', '<>', CallBase::FROM_DAILY_FREE],
            // ['from', '<>', CallBase::FROM_QUICK_MESSAGE],
            ['start_time', '<=', time() - 62]
        ];
        $count =  $callCls::where($where)->count();
        if ($count > 0) {
            $ret = $callCls::where($where)->update(['status' => CallBase::STATUS_INVALID]);
            log_info(__CLASS__ . "=={$callCls}==STATUS_INVALID==UpdateCount:{$count}");
        }

        //异常挂断记录状态（有一方30秒内没有更新通话时长）
        $nowTime = time();
        $where = [
            ['status', CallBase::STATUS_ING],
            ['heartbeat_user', '<', $nowTime - 30]
        ];
        $orWhere = [
            ['status', CallBase::STATUS_ING],
            ['heartbeat_chat', '<', $nowTime - 30]
        ];
        $count = $callCls::where($where)->orWhere(function ($query) use ($orWhere) {
            $query->where($orWhere);
        })->count();
        if ($count > 0) {
            //处理每条记录流水
            $callRecords = $callCls::where($where)->orWhere(function ($query) use ($orWhere) {
                $query->where($orWhere);
            })->get();
            foreach ($callRecords as $callRecord) {
                //结算话单
                $this->endCall($callRecord, $callCls);
            }
            log_info(__CLASS__ . "=={$callCls}==STATUS_ERR_HANGUP==UpdateCount:{$count}");
        }
    }

    /**
     * 结算话单
     */
    function endCall($callRecord = null, $callCls = VideoCall::class)
    {
        if (is_array($callRecord)) $callRecord = $callCls::find($callRecord['id']);
        if (!$callRecord) return;

        $callLock = ($callCls::CALL_TYPE == VideoCall::CALL_TYPE) ? RedisKey::operateVideoCallLock($callRecord->id) : RedisKey::operateVoiceCallLock($callRecord->id);
        //加同步锁
        if (!(RedisUtil::addLock($callLock, 5))) {
            log_info(__METHOD__ . "==endCallLock=={$callCls}==LogId:{$callRecord->id}");
            return;
        }

        //离开频道，更新话单状态
        $callRecord = CallBase::channelOutUpdate($callRecord, 1);
        if (!$callRecord) return;
        switch ($callRecord->from) {
                //免费福利单
            case CallBase::FROM_DAILY_FREE:
                //通话消费处理
                ConsumeService::settleCallForFree($callRecord, $callCls::CALL_TYPE);
                //免费券状态更新
                $freeCallLog = UserFreeCall::checkByCallId($callRecord->id, $callCls::CALL_TYPE);
                $freeCallLog && $freeCallLog->update([
                    'status' => UserFreeCall::STATUS_USED,
                    'used_minutes' => $freeCallLog->free_minutes,
                ]);
                break;
            case CallBase::FROM_INVITE_CALL:
                (new ConsumeService)->settleCallForInvite($callRecord,$callCls::CALL_TYPE);
                break;
                // 特惠视频
            case CallBase::FROM_DISCOUNT_CALL:
                ConsumeService::settleCallByDiscount($callRecord, VideoCall::CALL_TYPE);
                break;
                //其他单
            default:
                //通话消费处理
                ConsumeService::settleCall($callRecord, $callCls::CALL_TYPE);
                break;
        }

        //挂断事件
        EventUtil::dispatchHangup(
            $callRecord,
            $callCls::CALL_TYPE == VideoCall::CALL_TYPE ? 'video' : 'voice'
        );

        //透传消息给双方
        Message::sendSlient($callRecord->user_id, 'HANGUP_CALL');
        Message::sendSlient($callRecord->chat_user_id, 'HANGUP_CALL');

        //日志记录
        log_info(__METHOD__ . "=={$callCls}==LogId:{$callRecord->id}");
    }
}
